/**
 * 此示例演示如何HttpCrawler从外部文件中爬网 URL 列表、使用纯 HTTP 请求加载每个 URL 以及保存 HTML。
 */
import { Dataset, HttpCrawler, log, LogLevel } from 'crawlee';

// 爬虫带有各种实用程序，例如用于日志记录。
// 这里我们使用日志的调试级别来提高调试体验。
// 此功能是可选的！
log.setLevel(LogLevel.DEBUG);

// 创建HttpCrawler类的实例——爬虫
// 自动加载 URL 并保存其 HTML。
const crawler = new HttpCrawler({
    // 爬虫并行下载并处理网页，具有并发性
    // 根据可用系统内存和 CPU 自动管理（请参阅 AutoscaledPool 类）。
    // 这里我们定义了一些并发的硬性限制。
    minConcurrency: 10,
    maxConcurrency: 50,

    // 出现错误时，每个页面最多重试一次。
    maxRequestRetries: 1,

    // 增加每个页面处理的超时时间。
    requestHandlerTimeoutSecs: 30,

    // 每次抓取限制为 10 个请求
    maxRequestsPerCrawl: 10,

    // 每个要爬取的URL都会调用这个函数。
    // 它接受一个参数，这是一个带有选项的对象：
    // https://crawlee.dev/api/http-crawler/interface/HttpCrawlerOptions#requestHandler
    // 我们仅使用其中 2 个进行演示：
    // - request：Request类的实例，包含正在爬取的URL和HTTP方法等信息
    // - body：当前页面的HTML代码
    async requestHandler({ request, body }) {
        log.debug(`处理 ${request.url}...`);

        // 将结果存储到数据集。在本地配置中，
        // 数据将作为 JSON 文件存储在 ./storage/datasets/default 中
        await Dataset.pushData({
            url: request.url,
            body,
        });
    },

    // 如果页面处理失败超过 maxRequestRetries + 1 次，则调用此函数。
    failedRequestHandler({ request }) {
        log.debug(`Request ${request.url} failed twice.`);
    },
});

// 运行爬虫并等待其完成。
await crawler.run(['https://crawlee.dev']);

log.debug('爬虫完成!');
